package com.laity.pool;

import java.util.concurrent.*;

/**
 * @author: Laity
 * @Project: JavaLaity
 * @Package: com.laity.pool.Demo02
 * @Date: 2023年12月01日 11:03
 * @Description: 详解多线程七大参数以及自定义线程池
 */

public class Demo02 {
    // 给线程池直接提交任务 - 保证当前系统中只有一两个，每个异步任务交给线程池
    public static ExecutorService service = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /**
         * 1、继承Thread
         * 2、实现Runnable接口
         * 3、实现Callable接口 + FutureTask（可以拿到返回值，可以处理异常） jdk1.5
         * 4、线程池
         *      - 为什么用线程池 1、2、3，太浪费资源，尤其是高并发系统；
         *      - 将所有的多线程异步任务都交给线程池执行。
         *      - 降低资源的消耗
         *      - 提高响应速度
         *      - 提高线程的可管理性
         *    1、使用：
         *      1）、Executors 工具类
         *          public static ExecutorService service = Executors.newFixedThreadPool(10);
         *          service.execute(new Runnable01());
         *      2）、new ThreadPoolExecutor(); 原生
         * 区别：
         *      1、2没有返回值
         *      1、2、3不能控制资源；4可以，性能稳定。
         */
        Thread01 thread01 = new Thread01();
        thread01.start(); // 启动线程
        Runnable01 runnable01 = new Runnable01();
        new Thread(runnable01).start();
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        new Thread(futureTask).start();
        // 等待整个线程执行完成，获取的返回结果
        Integer integer = futureTask.get();
        System.out.println("Callable返回结果" + integer);
        // 给线程池直接提交任务 - 保证当前系统中只有一两个，每个异步任务交给线程池
        // service.submit()
        // service.execute();
        service.execute(new Runnable01());
        // 原生创建线程池
        /**
         * 七大参数
         *  int corePoolSize,    核心线程数量；线程池，创建好以后就准备就绪的线程数量，就等待来接收异步任务来执行
         *  int maximumPoolSize, 最大线程数量；控制资源
         *  long keepAliveTime,  存活时间；如果当前正在运行的线程数量大于核心线程数量。
         *                       释放空闲的线程资源（maximumPoolSize-corePoolSize），只要线程空闲大于指定的keepAliveTime；
         *  TimeUnit unit,       时间单位
         *  BlockingQueue<Runnable> workQueue,  阻塞队列；如果任务有很多， 大于maximumPoolSize的任务就会放到队列里面。
         *                                      只要有线程空闲，就会去队列里面抽取出新的任务继续执行。
         *                                      new LinkedBlockingQueue<>(); 默认是Integer的最大值
         *  ThreadFactory threadFactory,        线程的创建工厂。
         *  RejectedExecutionHandler handler    如果队列满了，按照我们指定的拒绝策略拒绝执行任务。
         *
         *  工作顺序：
         *  运行流程：
         *      1、线程池创建，准备好 core 数量的核心线程，准备接受任务
         *      2、新的任务进来，用 core 准备好的空闲线程执行。
         *          (1) 、core 满了，就将再进来的任务放入阻塞队列中。空闲的 core 就会自己去阻塞队列获取任务执行
         *          (2) 、阻塞队列满了，就直接开新线程执行，最大只能开到 max 指定的数量
         *          (3) 、max 都执行好了。Max-core 数量空闲的线程会在 keepAliveTime 指定的时间后自动销毁。最终保持到 core 大小
         *          (4) 、如果线程数开到了 max 的数量，还有新任务进来，就会使用 reject 指定的拒绝策略进行处理
         *      3、所有的线程创建都是由指定的 factory 创建的。
         */
        // Executors.defaultThreadFactory() 默认的线程工厂
        // new ThreadPoolExecutor.AbortPolicy() 丢弃拒绝策略 可自行查看源码，根据业务需求自行选用。
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 200,
                10, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10000),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
        executor.execute(new Runnable01());
        // Executors工具类可以帮我们创建的几种常见线程池
        // Executors.newCachedThreadPool() // 核心线程为0，所有线程都可回收；创建一个可缓存线程池，如果线程池长度超过处理需要，可灵活回收空闲线程，若无可回收，则新建线程。
        // Executors.newFixedThreadPool()  // 固定大小，core=max，都不可回收；创建一个定长线程池，可控制线程最大并发数，超出的线程会在队列中等待。
        // Executors.newScheduledThreadPool() // 定时任务线程池；创建一个定长线程池，支持定时及周期性任务执行。
        // Executors.newSingleThreadExecutor() // 单线程的线程池，后台从队列中获取任务顺序逐一执行；创建一个单线程化的线程池，它只会用唯一的工作线程来执行任务，保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行

    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.println("Thread当前线程" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println(i);
        }
    }

    public static class Runnable01 implements Runnable {
        @Override
        public void run() {
            System.out.println("Runnable当前线程" + Thread.currentThread().getId());
            int i = 12 / 2;
            System.out.println(i);
        }
    }

    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("Callable当前线程" + Thread.currentThread().getId());
            return 14 / 2;
        }
    }
}
